﻿using Dm;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using RuoVea.DynamicWebApi;
using RuoVea.ExDto;
using RuoVea.ExEnum;
using RuoVea.ExSugar;
using RuoVea.ExSugar.Entity;
using RuoVea.ExUtil;
using RuoVea.OmiApi.Article.Entitys;
using RuoVea.OmiApi.Article.Service.Dto;
using System.ComponentModel;
using System.Linq.Expressions;
using exDtoi18n = RuoVea.ExDto.Language.i18n;
using exUtili18n = RuoVea.ExUtil.Language.i18n;

namespace RuoVea.OmiApi.Article.Service;

/// <summary>
/// 分类管理 🔷
/// </summary>
[ApiExplorerSettings(GroupName = "art")]
public class CategoryService : IApplicationService
{
    private readonly SugarRepository<ArtCategory> _thisRepository;
    private readonly SugarRepository<ArtCategoryArticle> _artCategoryArticleRepository;

    /// <summary>
    /// 参数配置表
    /// </summary>
    /// <param name="thisRepository"></param>
    /// <param name="artCategoryArticleRepository"></param>
    public CategoryService(SugarRepository<ArtCategory> thisRepository, SugarRepository<ArtCategoryArticle> artCategoryArticleRepository)
    {
        _thisRepository = thisRepository;
        _artCategoryArticleRepository = artCategoryArticleRepository;
    }

    /// <summary>
    /// 查询所有/分页🔹
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    public virtual async Task<PageResult<CategoryDto>> GetPagesAsync([FromQuery] CategoryParam data)
    {
        var code = !string.IsNullOrEmpty(data.Code?.Trim());
        var name = !string.IsNullOrEmpty(data.Name?.Trim());

        var query = await _thisRepository.AsQueryable()
            .Includes(u => u.Children)
           .WhereIF(data.PId != null, u => u.PId == data.PId)
            .WhereIF(code, u => u.Code.Contains(data.Code))
            .WhereIF(name, u => u.Name.Contains(data.Name))
            .WhereIF(data.IsDisable != null, u => u.IsDisable == data.IsDisable)
            .OrderBy(u => u.Sort)
            .ToPageAsync<ArtCategory, CategoryDto>(data.PageNo, data.PageSize);
        return query;
    }

    /// <summary>
    /// 查询所有/分页🔹
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    public virtual async Task<PageResult<CategoryTreeDto>> GetTreePagesAsync([FromQuery] CategoryParam data)
    {
        var code = !string.IsNullOrEmpty(data.Code?.Trim());
        var name = !string.IsNullOrEmpty(data.Name?.Trim());

        // 先查询所有数据
        var allCategories = await _thisRepository.AsQueryable()
            .WhereIF(code, u => u.Code.Contains(data.Code))
            .WhereIF(name, u => u.Name.Contains(data.Name))
            .WhereIF(data.IsDisable != null, u => u.IsDisable == data.IsDisable)
            .OrderBy(u => u.Sort)
            .ToListAsync();

        // 构建树形结构
        var treeData = BuildTree(allCategories, data.PId);

        // 分页处理
        var pagedData = treeData
            .Skip((data.PageNo - 1) * data.PageSize)
            .Take(data.PageSize)
            .ToList();

        return new PageResult<CategoryTreeDto>(data.PageNo, data.PageSize)
        {
            TotalRows = treeData.Count,
            Rows = pagedData
        };
    }

    /// <summary>
    /// 构建树形结构
    /// </summary>
    /// <param name="allCategories">所有分类数据</param>
    /// <param name="parentId">父级ID，0表示顶级</param>
    /// <returns></returns>
    private List<CategoryTreeDto> BuildTree(List<ArtCategory> allCategories, long? parentId = 0)
    {
        var result = new List<CategoryTreeDto>();

        // 查找当前层级的节点
        var currentLevelNodes = allCategories
            .Where(x => x.PId == parentId)
            .OrderBy(x => x.Sort)
            .ToList();

        foreach (var node in currentLevelNodes)
        {
            var dto = new CategoryTreeDto
            {
                Id = node.Id,
                Name = node.Name,
                Code = node.Code,
                PId = node.PId,
                Sort = node.Sort,
                IsDisable = node.IsDisable,
                Remark = node.Remark,
            };

            // 递归构建子节点
            dto.Children = BuildTree(allCategories, node.Id);
            result.Add(dto);
        }

        return result;
    }

    /// <summary>
    /// 根据主键查询🔹
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    public virtual async Task<CategoryDto> GetDataAsync([FromQuery] EntityBaseId data)
    {
        var model = await _thisRepository
            .AsQueryable()
            .Includes(u => u.Children)
            .Where(x => x.Id == data.Id).FirstAsync();
        return model.Adapt<CategoryDto>();
    }
    
    /// <summary>
    /// 获取分类和下面的文章列表
    /// </summary>
    /// <returns></returns>
    [NonAction]
    public virtual async Task<List<ArtCategory>> GetEnableCategoryArticles(Expression<Func<ArtCategory, bool>> expression, YesOrNot isDisable= YesOrNot.N)
    {
        var model = await _thisRepository
            .AsQueryable()
            .Includes(x => x.Articles)
            .Where(x=>x.IsDisable== isDisable)
            .Where(expression)
            .ToListAsync();
        return model;
    }

    /// <summary>
    /// 获取分类和下面的文章列表
    /// </summary>
    /// <returns></returns>
    [NonAction]
    public virtual async Task<List<ArtCategory>> GetPushCategoryArticles(Expression<Func<ArtCategory, bool>> expression, int status = 1)
    {
        var model = await _thisRepository
            .AsQueryable()
            .Includes(x => x.Articles)
            .Where(x => x.Articles.Any(c=>c.Status== status))
            .Where(x => x.IsDisable ==  YesOrNot.N)
            .Where(expression)
            .ToListAsync();
        return model;
    }
    /// <summary>
    /// 获取分类和下面的文章列表
    /// </summary>
    /// <returns></returns>
    [NonAction]
    public virtual async Task<List<ArtCategory>> GetCategoryArticles(Expression<Func<ArtCategory, bool>> expression)
    {
        var model = await _thisRepository
           .AsQueryable()
           .Includes(x => x.Articles)
           .Where(expression)
           .ToListAsync();
        return model;
    }
    /// <summary>
    /// 获取列表🔹
    /// </summary>
    /// <returns></returns>
    [DisplayName("获取列表")]
    public async Task<List<CategoryOutput>> GetList([FromQuery] CategoryQuery data)
    {
        var model = await _thisRepository
           .AsQueryable()
           .WhereIF(data.IsDisable != null, u => u.IsDisable == data.IsDisable)
           .WhereIF(data.IsRoot != null && data.IsRoot == YesOrNot.Y, u => u.PId == 0)
           .WhereIF(data.IsRoot != null && data.IsRoot == YesOrNot.N, u => u.PId != 0)
           .WhereIF(data.UserId != null, u => u.Creator == data.UserId)
           .Includes(u => u.Children).ToListAsync();
        return model.Adapt<List<CategoryOutput>>();
    }

    /// <summary>
    /// 获取列表🔹
    /// </summary>
    /// <returns></returns>
    [DisplayName("获取列表")]
    public List<ArtIdCodeName> GetListByPage(CategoryParam data)
    {
        var query = _thisRepository.AsQueryable()
           .WhereIF(data.IsDisable != null, u => u.IsDisable == data.IsDisable)
            .OrderByDescending(u => u.CreateTime)
            .OrderBy(u => u.Sort)
            .Select(u => new ArtIdCodeName { Id = u.Id, Code = u.Code, Name = u.Name });
        return query.ToPageList(data.PageNo, data.PageSize);
    }

    /// <summary>
    /// 添加🔹
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    public virtual async Task<bool> AddDataAsync([FromBody] CategoryInputDto data)
    {
        if (data == null)
            throw new ArgumentException(ErrorEnum.D1504.GetDescription(exDtoi18n.ResourceManager));

        var isExist = await _thisRepository.IsAnyAsync(u => (u.Name == data.Name || u.Code == data.Code) && u.IsDelete == 0);

        if (isExist) throw new ArgumentException(ErrorEnum.D9000.GetDescription(exDtoi18n.ResourceManager));
        data.PId = data.PId ?? 0;
        var dictType = data.Adapt<ArtCategory>();

        return await _thisRepository.InsertAsync(dictType);
    }

    /// <summary>
    /// 修改🔹
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    public virtual async Task UpdateDataAsync([FromBody] CategoryInputDto data)
    {
        if (data == null)
            throw new ArgumentException(ErrorEnum.D1504.GetDescription(exDtoi18n.ResourceManager));

        if (data.Id <= 0)
            throw new AggregateException(string.Format(exUtili18n.invalidintegerformat, "Id"));

        var isExist = await _thisRepository.IsAnyAsync(u => u.Id == data.Id);
        if (!isExist) throw new ArgumentException(ErrorEnum.D1002.GetDescription(exDtoi18n.ResourceManager));

        // 排除自己并且判断与其他是否相同
        isExist = await _thisRepository.IsAnyAsync(u => (u.Name == data.Name || u.Code == data.Code) && u.Id != data.Id && u.IsDelete == 0);
        if (isExist) throw new ArgumentException(ErrorEnum.D9000.GetDescription(exDtoi18n.ResourceManager));
        data.PId = data.PId ?? 0;
        var dictType = data.Adapt<ArtCategory>();

        await _thisRepository.UpdateAsync(dictType);
    }

    /// <summary>
    /// 删除🔹
    /// </summary>
    /// <param name="data"></param>
    /// <returns></returns>
    [HttpDelete]
    public virtual async Task DeleteDataAsync([FromBody] EntityBaseId data)
    {
        if (data == null)
            throw new ArgumentException(ErrorEnum.D1504.GetDescription(exDtoi18n.ResourceManager));

        data.Check();

        var dictType = await _thisRepository.GetFirstAsync(u => u.Id == data.Id);
        if (dictType == null) throw new ArgumentException(ErrorEnum.D1002.GetDescription(exDtoi18n.ResourceManager));

        var isAnyPId = await _thisRepository.IsAnyAsync(u => u.PId == data.Id);
        if (isAnyPId) throw new ArgumentException(ErrorEnum.D1007.GetDescription(exDtoi18n.ResourceManager));
        // 有文章不让删除
        bool isAny = await _artCategoryArticleRepository.IsAnyAsync(x => x.CategoryId == dictType.Id);
        if (isAny) throw new ArgumentException(ErrorEnum.D1007.GetDescription(exDtoi18n.ResourceManager));

        if (dictType.IsDelete == IsDelete.Y)
            await _thisRepository.DeleteByIdAsync(data.Id);
        else
        {
            dictType.IsDelete = IsDelete.Y;

            await _thisRepository.UpdateAsync(dictType);
        }
    }
}